package org.ehe.business.ocr.service.impl;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.ehe.business.ocr.domain.OcrLicenseResult;
import org.ehe.business.ocr.property.BaiduOcrProperties;
import org.ehe.business.ocr.service.OcrService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author :zhangnn
 * @className :BusinessLicenseOcrServiceImpl
 * @description: TODO
 * @date 2025-07-22 16:33:06
 */
@Slf4j
@Service
public class OcrServiceImpl implements OcrService {

    @Autowired
    private BaiduOcrProperties ocrProperties;
    private final Gson gson = new Gson();
    private final ConcurrentHashMap<String, String> tokenCache = new ConcurrentHashMap<>();
    private final ReentrantLock tokenLock = new ReentrantLock();


    /**
     * 识别营业执照
     */
    @Override
    public OcrLicenseResult recognizeFromFile(MultipartFile file) {
        try {
            if (file.isEmpty()) {
                throw new IllegalArgumentException("上传文件不能为空");
            }

            // 验证文件类型
            String contentType = file.getContentType();
            if (contentType == null || !contentType.startsWith("image/")) {
                throw new IllegalArgumentException("只支持图片格式文件");
            }

            // 验证文件大小（10MB）
            if (file.getSize() > 10 * 1024 * 1024) {
                throw new IllegalArgumentException("文件大小不能超过10MB");
            }

            // 转换为Base64
            byte[] fileBytes = file.getBytes();
            String base64Image = Base64.getEncoder().encodeToString(fileBytes);

            return recognizeBusinessLicense(base64Image, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 识别方法
     */
    private OcrLicenseResult recognizeBusinessLicense(String base64Image, String imageUrl) throws Exception {
        String accessToken = getAccessToken();
        String url = ocrProperties.getOcrUrl() + "?access_token=" + accessToken;

        HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(30000);
        conn.setDoOutput(true);

        // 构建请求参数
        StringBuilder params = new StringBuilder();
        if (base64Image != null) {
            params.append("image=").append(URLEncoder.encode(base64Image, StandardCharsets.UTF_8));
        } else if (imageUrl != null) {
            params.append("url=").append(URLEncoder.encode(imageUrl, StandardCharsets.UTF_8));
        }

        // 发送请求
        try (OutputStream os = conn.getOutputStream()) {
            os.write(params.toString().getBytes(StandardCharsets.UTF_8));
        }

        int responseCode = conn.getResponseCode();
        if (responseCode == 200) {
            String response = readResponse(conn.getInputStream());
            log.info("OCR识别成功，响应: {}", response);
            return parseBusinessLicenseResult(response);
        } else {
            String errorResponse = readResponse(conn.getErrorStream());
            log.error("OCR识别失败，响应码: {}, 错误信息: {}", responseCode, errorResponse);
            throw new RuntimeException("OCR识别失败: " + errorResponse);
        }
    }

    /**
     * 获取访问令牌
     */
    private String getAccessToken() throws Exception {
        String cacheKey = ocrProperties.getApiKey();
        String cachedToken = tokenCache.get(cacheKey);

        if (cachedToken != null) {
            return cachedToken;
        }

        tokenLock.lock();
        try {
            // 双重检查锁定
            cachedToken = tokenCache.get(cacheKey);
            if (cachedToken != null) {
                return cachedToken;
            }

            String url = ocrProperties.getTokenUrl() + "?grant_type=client_credentials"
                + "&client_id=" + ocrProperties.getApiKey()
                + "&client_secret=" + ocrProperties.getSecretKey();

            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(10000);

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                String response = readResponse(conn.getInputStream());
                JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
                String token = jsonObject.get("access_token").getAsString();

                // 缓存token（有效期通常为30天，这里设置为25天后失效）
                tokenCache.put(cacheKey, token);
                log.info("获取访问令牌成功");
                return token;
            } else {
                String errorResponse = readResponse(conn.getErrorStream());
                log.error("获取访问令牌失败，响应码: {}, 错误信息: {}", responseCode, errorResponse);
                throw new RuntimeException("获取访问令牌失败: " + errorResponse);
            }
        } finally {
            tokenLock.unlock();
        }
    }

    /**
     * 解析营业执照识别结果
     */
    private OcrLicenseResult parseBusinessLicenseResult(String jsonResponse) throws Exception {
        try {
            JsonObject jsonObject = gson.fromJson(jsonResponse, JsonObject.class);

            // 检查是否有错误
            if (jsonObject.has("error_code")) {
                String errorMsg = jsonObject.get("error_msg").getAsString();
                log.error("百度OCR API返回错误: {}", errorMsg);
                throw new RuntimeException("OCR识别失败: " + errorMsg);
            }

            // 解析营业执照信息
            JsonObject wordsResult = jsonObject.getAsJsonObject("words_result");

            return new OcrLicenseResult(
                getFieldValue(wordsResult, "社会信用代码"),
                getFieldValue(wordsResult, "单位名称"),
                getFieldValue(wordsResult, "法人"),
                getFieldValue(wordsResult, "地址"),
                getFieldValue(wordsResult, "成立日期"),
                getFieldValue(wordsResult, "营业期限"),
                getFieldValue(wordsResult, "经营范围"),
                getFieldValue(wordsResult, "注册资本"),
                getFieldValue(wordsResult, "证件编号"),
                getFieldValue(wordsResult, "类型")
            );

        } catch (Exception e) {
            log.error("解析识别结果失败", e);
            throw new RuntimeException("解析识别结果失败: " + e.getMessage());
        }
    }
    /**
     * 从JSON对象中获取字段值
     */
    private String getFieldValue(JsonObject wordsResult, String fieldName) {
        try {
            if (wordsResult != null && wordsResult.has(fieldName)) {
                JsonObject fieldObject = wordsResult.getAsJsonObject(fieldName);
                if (fieldObject != null && fieldObject.has("words")) {
                    return fieldObject.get("words").getAsString();
                }
            }
        } catch (Exception e) {
            log.warn("获取字段 {} 的值时出现异常", fieldName, e);
        }
        return "";
    }

    /**
     * 读取HTTP响应
     */
    private String readResponse(InputStream inputStream) throws IOException {
        if (inputStream == null) return "";

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        }
    }

    /**
     * 清除token缓存
     */
    public void clearTokenCache() {
        tokenCache.clear();
        log.info("已清除访问令牌缓存");
    }

}
